package com.xlw.authenticator;

import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.xlw.api.AndroidOnRoadUrlFactory;
import com.xlw.exception.AndroidOnRoadException;
import com.xlw.utils.HttpUtil;

/**
 * 这个类实现登录功能.登录功能会在以下情况下用到:
    1. 应用程序启动时还没有账户信息被创建
    2. 用户在"账户&同步"菜单中点击"新建账户"
    3. 同步适配器尝试同步数据时出现身份验证错误
   这个类的目的是为了处理第二种情况.这种情况相对要复杂些,需要为最后一种情况预备好所有必需条件.
   要在设置中通过"账户&同步"菜单创建新账户,需要添加一个继承自AbstractAccountAuthenticator的类.
 AbstractAccountAuthenticator是用于创建账户认证器的基类.
 要提供一个新的认证器,必须继承自AbstractAccountAuthenticator,并实现其抽象方法.此外,还需要创建
 一个Service(即AuthenticationService)
 *
 * Created by xinliwei on 2015/7/7.
 *
 * 自定义一个新的认证器,必须继承自AbstractAccountAuthenticator,并实现其抽象方法
 * 用来创建账户认证器.其中比较重要的方法是addAccount()和getAuthToken()方法
 */
public class Authenticator extends AbstractAccountAuthenticator{

    private final Context mContext;

    public Authenticator(Context context) {
        super(context);
        this.mContext = context;
    }

    @Override
    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
        return null;
    }

    /**
     * 这个方法创建一个Intent,AccountManager会使用该Intent创建新账户.
     * @param response          响应对象
     * @param accountType       账户类型
     * @param authTokenType     授权令牌类型
     * @param requiredFeatures  请求特性
     * @param options           数据包
     * @return                  数据包
     * @throws NetworkErrorException    网络异常
     */
    @Override
    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
                             String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {

        final Intent intent = new Intent(mContext,AuthenticatorActivity.class);
        intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE,authTokenType);
        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,response);
        final Bundle bundle = new Bundle();
        bundle.putParcelable(AccountManager.KEY_INTENT,intent);

        return bundle;
    }

    @Override
    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
        return null;
    }

    /**
     * 当需要使用账户中存储的用户凭证信息登录服务器时,该方法就会被调用.
     * 该方法首先检查请求的令牌是否与当前处理的令牌相同,然后通过AccountManager获取密码
     * 如果获取到密码,就以此登录服务器.如果登录成功,就返回登录结果;如果登录不成功,就返回
     * 一个Intent,通过该Intent告诉调用者启动哪个Activity让用户重新登录.
     * 当密码改变或者用户凭证失效时会出现上述情况.
     * @param response
     * @param account
     * @param authTokenType
     * @param options
     * @return
     * @throws NetworkErrorException
     */
    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
                               String authTokenType, Bundle options) throws NetworkErrorException {
        // 检查请求的令牌是否相同
        if(!authTokenType.equals(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE)){
            final Bundle result = new Bundle();
            result.putString(AccountManager.KEY_ERROR_MESSAGE,"无效的authTokenType");
            return result;
        }

        final AccountManager am = AccountManager.get(mContext);
        // 获取密码
        final String password = am.getPassword(account);
        if(password != null){
            boolean verified = false;
            String loginResponse = null;

            // 使用账号和密码登录服务器
            try{
                // 获得登录的URL.格式化URL字符串,将账号和密码作为查询字符串参数
                String url = AndroidOnRoadUrlFactory.getInstance().getLoginUrlFmt();
                String url_req = String.format(url,account.name,password);
                loginResponse = HttpUtil.getHttpResponseAsString(url_req);
                verified = "{\"result\": \"ok\"}".equals(loginResponse);
            }catch (AndroidOnRoadException e){
                verified = false;
            }

            // 如果登录成功,就返回结果.
            if(verified){
                final Bundle result = new Bundle();
                result.putString(AccountManager.KEY_ACCOUNT_NAME,account.name);
                result.putString(AccountManager.KEY_ACCOUNT_TYPE,AuthenticatorActivity.PARAM_ACCOUNT_TYPE);

                return result;
            }
        }

        // 如果登录不成功,让调用方知道应该启动哪个Activity让用户登录
        final Intent intent = new Intent(mContext,AuthenticatorActivity.class);
        intent.putExtra(AuthenticatorActivity.PARAM_USER,account.name);
        intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE,authTokenType);
        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,response);
        final Bundle bundle = new Bundle();
        bundle.putParcelable(AccountManager.KEY_INTENT,intent);
        return bundle;
    }

    @Override
    public String getAuthTokenLabel(String authTokenType) {
        return null;
    }

    @Override
    public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
                                    String authTokenType, Bundle options) throws NetworkErrorException {
        return null;
    }

    @Override
    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
                              String[] features) throws NetworkErrorException {
        return null;
    }
}
